<?php

declare(strict_types=1);
/**
 * 
 */
namespace WanZ\App\User\Logic\Traits;

use Hyperf\DbConnection\Db;
use Hyperf\Context\Context;
use WanZ\App\User\Contract\UserBaseContract;
use WanZ\App\User\Contract\WzUserAttributeContract;
use WanZ\App\User\Contract\UserDiscardContract;
use WanZ\App\User\Model\UserWxOpenidRecord;
use WanZ\App\Utils\Snowflake;
use MoChat\Framework\Constants\ErrorCode;
use MoChat\Framework\Exception\CommonException;

trait UserTrait
{
    /**
     * 通过用户ID获取用户基础信息
     *
     * @param int $userId
     * @param array $fields
     * @return array
     * @throws CommonException
     * @throws DatabaseException
     */
    public function getUserBaseInfoByUserId(int $userId, array $fields = []): array
    {
        $userBaseInfo = make(UserBaseContract::class)->getUserBaseByUserId($userId, $fields);
        if (empty($userBaseInfo)) {
            throw new CommonException(ErrorCode::SERVER_ERROR, '当前用户不存在，不可操作');
        }

        $res = $userBaseInfo->toArray();
        $res['id'] = $res['userId'];
        return $res;
    }

    /**
     * 通过用户手机号获取用户基础信息
     *
     * @param string $phone
     * @param array $fields
     * @return array
     * @throws CommonException
     * @throws DatabaseException
     */
    public function getUserBaseInfoByPhone(string $phone, array $fields = []): array
    {
        $userBaseInfo = make(UserBaseContract::class)->getUserBaseByPhone($phone, $fields);
        if (empty($userBaseInfo)) {
            throw new CommonException(ErrorCode::SERVER_ERROR, '当前用户不存在，不可操作');
        }

        $res = $userBaseInfo->toArray();
        $res['id'] = $res['userId'];
        return $res;
    }

    /**
     * 通过用户ID获取用户信息
     * @param int $userId
     * @param array $fields
     * @param array $fields2
     * @return array 响应数组
     */   
    protected function getUserInfo(int $userId = 0, array $fields = [], array $fields2 = []) : array
    {
        $baseRes = $attrRes = [];

        $userBaseInfo = make(UserBaseContract::class)->getUserBaseByUserId($userId, $fields);  
        if (empty($userBaseInfo)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '当前用户不存在，不可操作');
        }
        $baseRes = $userBaseInfo->toArray();

        $userAttrInfo = make(WzUserAttributeContract::class)->getUserAttrByUserId($userId, $fields2);
        if (empty($userAttrInfo)) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '当前用户不存在，不可操作');
        }  
        $attrRes = $userAttrInfo->toArray();
        $attrRes['id'] = $attrRes['userId'];     

        return array_merge($baseRes, $attrRes);
    }

    /**
     * 判断手机号是否存在，，TRUE => 存在
     * 注册（绑定）手机号的时候，需要传递$type (ali , wx)，来判断是通信WX注册还是ALI注册
     * @param string $phone
     * @param string $type
     * @return bool
     * @throws CommonException
     */
    public function checkPhoneExists(string $phone = "", $type = "") : bool
    {
        if (empty($phone)) {
            return false;
        }
        try {
            $userBaseInfo = make(UserBaseContract::class)->getUserBaseByPhone($phone);  
            if (empty($userBaseInfo)) {
                throw new CommonException(ErrorCode::INVALID_PARAMS, '当前用户不存在，不可操作');
            }
            return true;
        } catch (\Throwable $exception) {
            return false;
        }
    }

    /**
     * 根据小程序OPENID和UNIONID，获取用户信息，没有则注册新用户
     * @param string $wxMiniOpenid
     * @return array
     * @throws CommonException
     */
    public function getByWxMiniOpenId(string $wxMiniOpenid = '') : array
    {
        if (empty($wxMiniOpenid)) return [];
        $userAttr = make(WzUserAttributeContract::class)->getUserAttrByWxMiniOpenId($wxMiniOpenid, ['user_id']);
        if (empty($userAttr)) {
            $userAttr['nick_name'] = '';
            $userAttr['wx_unionid'] = '';
            $userAttr['wx_mini_openid'] = $wxMiniOpenid;
            $userAttr['user_id'] = make(Snowflake::class)->generatedUniqueId();
            if (!make(WzUserAttributeContract::class)->createUserAttr($userAttr)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '注册新用户失败');
            }

            $userAttr['id'] = $userAttr['user_id'];
        } else {
            $userAttr['id'] = $userAttr['userId'];
        }

        return $userAttr;
    }

    /**
     * 通过微信UNIONDID获取用户信息，没有则注册
     * @param string $wxUnionid
     * @param string $wxMiniOpenid
     * @return array
     * @throws CommonException
     */
    public function getByWxUnionId(string $wxUnionid = '', string $wxMiniOpenid = '') : array
    {
        if (empty($wxUnionid)) return [];
        $userAttr = make(WzUserAttributeContract::class)->getUserAttrByWxUnionId($wxUnionid, ['user_id', 'wx_mini_openid', 'nickname']);
        if (empty($userAttr)) {
            $userAttr['nickname'] = '';
            $userAttr['wx_unionid'] = $wxUnionid;
            $userAttr['wx_mini_openid'] = $wxMiniOpenid;
            $userAttr['user_id'] = make(Snowflake::class)->generatedUniqueId();
            if (!make(WzUserAttributeContract::class)->createUserAttr($userAttr)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '无法注册新用户');
            }

            $userAttr['id'] = $userAttr['user_id'];
            $userAttr['wxMiniOpenid'] = $wxMiniOpenid;
        } else {
            $userAttr['id'] = $userAttr['userId'];
        }

        // 老用户第1次登录新平台，更新miniOpenid
        if (!empty($userAttr) && (empty($userAttr['wxMiniOpenid']) || ($userAttr['wxMiniOpenid'] != $wxMiniOpenid && $wxMiniOpenid != ''))) {
            $userAttr['wx_mini_openid'] = $wxMiniOpenid;
            make(WzUserAttributeContract::class)->updateUserAttrByUserId((int) $userAttr['id'], ['wx_mini_openid' => $wxMiniOpenid]);
        }

        $miniType = Context::get('minSource', 'wz');
        UserWxOpenidRecord::updateOrCreate(
            ['user_id' => $userAttr['id'], 'mini_type' => $miniType],
            ['wx_unionid' => $wxUnionid, 'wx_mini_openid' => $wxMiniOpenid]
        );

        return $userAttr;
    }

    /**
     * 根据ALI的OPENID获取用户信息
     * @param string $aliMiniOpenid
     * @return array
     * @throws CommonException
     */
    public function getByAliMiniOpenId(string $aliMiniOpenid = ''): array
    {
        if (empty($aliMiniOpenid)) {
            return [];
        }

        $userAttr = make(WzUserAttributeContract::class)->getUserAttrByAliMiniOpenId($aliMiniOpenid, ['user_id']);
        // 2020-09-26，没有数据，则新增。业务上的理解是：有auth_code，就能成为用户。绑定手机号为后续操作。
        if (empty($userAttr)) {
            $userAttr['nick_name'] = '';
            $userAttr['ali_openid'] = $aliMiniOpenid;

            $userAttr['user_id'] = make(Snowflake::class)->generatedUniqueId();

            if (!make(WzUserAttributeContract::class)->createUserAttr($userAttr)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '注册新用户失败');
            }
            $userAttr['id'] = $userAttr['user_id'];
        } else {
            $userAttr['id'] = $userAttr['userId'];
        }

        return $userAttr;
    }

    /**
     * 用户是否开通了微信支付分功能
     *
     * @param string $phone
     * @return int
     * @throws CommonException
     */
    public function isOpenWxPayScoreByUserPhone(string $phone = ''): int
    {
        // 暂时没用，直接返回
        return 0;

        if (empty($phone)) {
            return 0;
        }

        //TODO
    }

    /**
     * 获取支付宝芝麻后付开通协议号和开通状态
     *
     * @param string $phone
     * @return string[]
     * @throws CommonException
     */
    private function getAliCreditCreditAgreementIdByPhone(string $phone): array
    {
        $creditAgrId = '';
        $state = 0;

        // 暂时没用，直接返回
        return [$creditAgrId, $state];

        //TODO
    }

    /**
     * 是否开通数字人民币
     * @param string $phone
     * @return bool
     */
    private function isOpenDigitalRmb(string $phone): bool
    {
        // 暂时没用，直接返回
        return false;

        if (empty($phone)) {
            return false;
        }

        //TODO
    }  


    /**
     * 更新手机号
     *
     * @param int $userId
     * @param string $phone
     * @param string $type
     * @return bool
     * @throws CommonException
     */
    public function updateUserPhone(int $userId = 0, string $phone = '', string $type = ''): bool
    {
        if (!checkPhone($phone) || $userId <= 0 || !in_array($type, ['wx', 'ali'])) {
            throw new CommonException(ErrorCode::INVALID_PARAMS, '绑定手机号失败，参数非法');
        }

        try {
            $data = make(UserBaseContract::class)->getUserBaseByPhone($phone); 
            if (empty($data)) {
                $this->addValidClientUser($phone, $userId);
            } else {
                $this->handleExistsUser($userId, $data, $type);
            }
        } catch (\Throwable $exception) {
            throw $exception;
        }

        return true;
    }    

    /**
     * 根据手机号添加一个新的有效用户
     *
     * @param $phone
     * @param $currentLoginUserId
     * @return int
     */
    private function addValidClientUser(string $phone, int $currentLoginUserId): int
    {
        $historyRes = make(UserBaseContract::class)->getUserBaseByUserId((int)$currentLoginUserId, ['phone', 'user_id']);
        if (!empty($historyRes)) {
            if ($historyRes['phone'] != $phone) {
                make(UserBaseContract::class)->updateUserBaseByUserId($currentLoginUserId, ['phone' => $phone]);
            }
            return $currentLoginUserId;
        }

        make(UserBaseContract::class)->createUserBase(['phone' => $phone, 'user_id' => $currentLoginUserId]);
        return $currentLoginUserId;
    }
    
    /**
     * 处理已经存在的用户
     *
     * @param int $currentLoginUserId
     * @param $data
     * @param $loginType
     * @return int
     */
    private function handleExistsUser(int $currentLoginUserId, $data, $loginType): int
    {
        $phoneRelUserId = (int) $data['userId'];

        if ($currentLoginUserId == $phoneRelUserId) {
            return $currentLoginUserId;
        }

        list($currentLoginUserInfo, $isExistsRes) = $this->getUserOtherInfoByUserId($currentLoginUserId, $phoneRelUserId, $loginType);

        if ($isExistsRes) {
            $loginType == 'ali' && $waitUpData = ['ali_openid'     => $currentLoginUserInfo['aliOpenid']];
            $loginType == 'wx'  && $waitUpData = ['wx_mini_openid' => $currentLoginUserInfo['wxMiniOpenid'], 'wx_unionid' => $currentLoginUserInfo['wxUnionid']];

            return $this->updateUserInfoHasExists(
                $phoneRelUserId,
                $currentLoginUserId,
                $loginType,
                $waitUpData,
                $currentLoginUserInfo
            );
        }

        return $this->updateUserInfoHasNotExists($currentLoginUserId, $phoneRelUserId);
    }

        /**
     * 根据用户的登陆类型获取值
     *
     * @param int $currentLoginUserId
     * @param int $phoneRelevanceUserId
     * @param $type
     * @return array
     * @throws CommonException
     * @throws DatabaseException
     */
    private function getUserOtherInfoByUserId(int $currentLoginUserId, int $phoneRelevanceUserId, $type): array
    {
        $oldUserInfo = make(WzUserAttributeContract::class)->getUserAttrByUserId($currentLoginUserId);
        $attrInfo = make(WzUserAttributeContract::class)->getUserAttrByUserId($phoneRelevanceUserId, ['ali_openid', 'wx_mini_openid']);

        if (empty($attrInfo)) {
            return [$oldUserInfo, false];
        }

       /* if ($type == 'ali' && !empty($attrInfo['aliOpenid'])) {
            throw new DatabaseException('该手机号已被绑定，请联系管理员', ErrorCode::DATABASE_DATA_ERROR_CODE);
        }

        if ($type == 'wx' && !empty($attrInfo['wxMiniOpenid'])) {
            throw new DatabaseException('该手机号已被绑定，请联系管理员', ErrorCode::DATABASE_DATA_ERROR_CODE);
        }*/

        return [$oldUserInfo, true];
    }

    /**
     * 更新已经存在的用户
     * @param int $phoneRelUserId
     * @param int $currentLoginUserId
     * @param $loginType
     * @param $waitUpData
     * @param $oldUserInfo
     * @return int
     * @throws CommonException
     */
    private function updateUserInfoHasExists(int $phoneRelUserId, int $currentLoginUserId, $loginType, $waitUpData, $oldUserInfo): int
    {
        //开启事务
        Db::connection('default')->beginTransaction();
        try {
            if (!make(WzUserAttributeContract::class)->updateUserAttrByUserId($phoneRelUserId, $waitUpData)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '更新用户手机号失败');
                
            }

            $addRes = make(UserDiscardContract::class)->addUserForDiscard([
                'del_user_id' => $currentLoginUserId,
                'new_user_id' => $phoneRelUserId,
                'inter_platform' => 'bicycles',
                'outer_platfrom' => $loginType,
                'otherData'      => json_encode($oldUserInfo, 320),
                'discard_at'     => date('Y-m-d H:i:s')
            ]);

            if (!$addRes) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '添加用户记录失败');
            }

            if (!make(WzUserAttributeContract::class)->deleteUserAttrByUserId($currentLoginUserId)) {
                throw new CommonException(ErrorCode::SERVER_ERROR, '删除旧用户信息失败');
            }
            Db::connection('default')->commit();
        } catch (\Throwable $e) {
            Db::connection('default')->rollBack();
            throw new CommonException($e->getCode(), $e->getMessage());
        }

        return $phoneRelUserId;
    }  
    
    /**
     * 更新新进来的用户
     * @param int $userId
     * @param int $phoneRelUserId
     * @return int
     * @throws CommonException
     */
    private function updateUserInfoHasNotExists(int $userId, int $phoneRelUserId): int
    {
        if (!make(WzUserAttributeContract::class)->updateUserAttrByUserId($userId, ['user_id' => $phoneRelUserId])) {
            throw new CommonException(ErrorCode::SERVER_ERROR, '更新用户手机号失败');
        }

        return $phoneRelUserId;
    }    
    
}
